<?php

namespace Cloud;

use Cloud\Support\Algorithm;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server as SwoWsServer;
use Swoole\Http\Request as SwoRequest;
use Swoole\Http\Response as SwoResponse;

/**
 * 1. 检测IM-server的存活状态
 * 2. 支持权限认证
 * 3. 根据服务器的状态，按照一定的算法，计算出该客户端连接到哪台IM-server，返回给客户端，客户端再去连接到对应的服务端,保存客户端与IM-server的路由关系
 * 4. 如果 IM-server宕机，会自动从Redis中当中剔除
 * 5. IM-server上线后连接到Route，自动加 入Redis(im-server ip:port)
 * 6. 可以接受来自PHP代码、C++程序、Java程序的消息请求，转发给用户所在的IM-server
 * 7. 缓存服务器地址，多次查询redis
 *
 * 是一个websocket
 */
class Route extends Server
{
    /**
     * Note: 初始化事件
     *
     * @author: Zhao Zhiqiang
     * @since: 2021/5/11 17:25
     */
    protected function initEvent()
    {
        $this->setEvent('sub', [
            'request' => 'onRequest',
            'open' => 'onOpen',
            'message' => 'onMessage',
            'close' => 'onClose'
        ]);
    }

    /**
     * Note: 创建 Http 服务器
     *
     * @return void
     * @author: Zhao Zhiqiang
     * @since: 2021/5/11 17:29
     */
    public function createServer()
    {
        $this->swoServer = new SwoWsServer(
            $this->host,
            $this->port
        );
    }

    public function onRequest(SwoRequest $swoRequest, SwoResponse $swoResponse)
    {
        $uri = $swoRequest->server['request_uri'];
        if ($uri == '/favicon.ico') {
            $swoResponse->status(404);
            $swoResponse->end();
        }

        $data = $swoRequest->post;

        $this->getDispatcher()->{$data['method']}($this, $swoRequest, $swoResponse);
    }

    public function onOpen(SwoWsServer $swoServer, SwoRequest $swoRequest)
    {
    }

    public function onMessage(SwoWsServer $swoServer, Frame $frame)
    {
        $data = json_decode($frame->data, true);
        $fd = $frame->fd;

        $this->getDispatcher()->{$data['method']}($this, $swoServer, $fd, $data);
    }

    public function onClose(SwoWsServer $swoServer, int $fd)
    {

    }

    public function getDispatcher():Dispatcher
    {
        if (empty($this->dispatcher)) {
            $this->dispatcher = new Dispatcher;
        }

        return $this->dispatcher;
    }

    public function getRedis(): \Redis
    {
        return $this->redis;
    }

    public function getAlgorithm(): Algorithm
    {
        return $this->algorithm;
    }

    public function getServerKey(): string
    {
        return $this->serverKey;
    }
}